package com.up.mongo.utils;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.bson.json.JsonMode;
import org.bson.json.JsonWriterSettings;
import org.bson.json.StrictJsonWriter;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * MongoDB工具类
 * @Author fanxianping
 * @Date 2022/2/10 10:16
 */
public class MongoDBUtils {
    /**
     * 连接缓存
     */
    private final static Map<String,MongoTemplate> chacheMongoTemplates= new LinkedHashMap<>();
    public final static String DATE_FMT_4 = "yyyy-MM-dd HH:mm:ss";

    public final static JsonWriterSettings settings =
            JsonWriterSettings.builder()
                    .outputMode(JsonMode.EXTENDED)
                    .int64Converter((Long value, StrictJsonWriter writer) ->writer.writeString(Long.toString(value)))
                    .int32Converter((Integer value, StrictJsonWriter writer) ->writer.writeNumber(Integer.toString(value)))
                    .doubleConverter((Double value,StrictJsonWriter writer)->writer.writeNumber(Double.toString(value)))
                    .objectIdConverter((ObjectId value, StrictJsonWriter writer)->writer.writeString(value.toHexString()))
                    .dateTimeConverter((Long value, StrictJsonWriter writer)->writer.writeString(longToStrDate(value,DATE_FMT_4)))
                    .build();
    /**
     * 将时间戳转换成字符日期格式
     *
     * @param time
     * @param format
     * @return
     */
    public static String longToStrDate(long time, String format) {
        Date millisecondDate = new Date(time);
        //格式化时间
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        String strDate = formatter.format(millisecondDate);
        return strDate;
    }
    public static MongoClient getMongoClient(String collectionString){
        return MongoClients.create(collectionString);
    }

    /**
     * 获取MongoTemplate
     * @param collectionString
     * @return
     */
    public static MongoTemplate getMongoTemplate(String collectionString){
        if(chacheMongoTemplates.containsKey(collectionString)){{
            return chacheMongoTemplates.get(collectionString);
        }}
        SimpleMongoClientDatabaseFactory simpleMongoClientDatabaseFactory = new SimpleMongoClientDatabaseFactory(collectionString);

        MongoTemplate mongoTemplate = new MongoTemplate(simpleMongoClientDatabaseFactory,getMappingConverter(simpleMongoClientDatabaseFactory));
        chacheMongoTemplates.put(collectionString,mongoTemplate);
        return mongoTemplate;
    }
    /**
     * 获取MongoTemplate
     * @param collectionString
     * @return
     */
    public static MongoTemplate getMongoTemplate(String collectionString,String databaseName){
        if(chacheMongoTemplates.containsKey(collectionString+":target:"+databaseName)){{
            return chacheMongoTemplates.get(collectionString+":target:"+databaseName);
        }}
        SimpleMongoClientDatabaseFactory simpleMongoClientDatabaseFactory = new SimpleMongoClientDatabaseFactory(getMongoClient(collectionString),databaseName);

        MongoTemplate mongoTemplate = new MongoTemplate(simpleMongoClientDatabaseFactory,getMappingConverter(simpleMongoClientDatabaseFactory));
        chacheMongoTemplates.put(collectionString,mongoTemplate);
        return mongoTemplate;
    }

    /**
     * 获取转换器
     * @param simpleMongoClientDatabaseFactory
     * @return
     */
    private static MappingMongoConverter getMappingConverter(SimpleMongoClientDatabaseFactory simpleMongoClientDatabaseFactory){
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(simpleMongoClientDatabaseFactory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
        //去除_class字段
        mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return mappingConverter;
    }

    public static  <E> Query buildBaseQuery(E t) {
        Query query = new Query();

        Field[] fields = t.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(t);
                if (value != null) {
                    query.addCriteria(Criteria.where(field.getName()).is(value));
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        return query;
    }
}
